package biz.datalk.industrialland.admin.modules.system.service.impl;

import biz.datalk.industrialland.admin.component.shiro.CustomLoginUser;
import biz.datalk.industrialland.admin.modules.system.mapper.ISysFunctionExtMapper;
import biz.datalk.industrialland.admin.modules.system.pojo.dto.SysFunctionDTO;
import biz.datalk.industrialland.admin.modules.system.pojo.vo.MenuVO;
import biz.datalk.industrialland.admin.modules.system.service.ISysFunctionService;
import biz.datalk.industrialland.admin.modules.system.service.ISysUserService;
import biz.datalk.industrialland.admin.modules.util.ShiroUtil;
import biz.datalk.industrialland.common.def.enums.DBYNEnum;
import biz.datalk.industrialland.common.exception.ServiceException;
import biz.datalk.industrialland.common.result.UnifyResult;
import biz.datalk.industrialland.common.result.UnifyResultCode;
import biz.datalk.industrialland.common.result.UnifyResultUtil;
import biz.datalk.industrialland.common.util.EntityIdUtils;
import biz.datalk.industrialland.common.util.I18NUtil;
import biz.datalk.industrialland.mbg.mapper.SysFunctionMapper;
import biz.datalk.industrialland.mbg.pojo.po.SysFunction;
import biz.datalk.industrialland.mbg.pojo.po.SysRole;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author tarofang@163.com
 * @date 2019-09-09
 */
@Slf4j
@Service
public class SysFunctionServiceImpl implements ISysFunctionService {

    private final SysFunctionMapper sysFunctionMapper;
    private final ISysFunctionExtMapper sysFunctionExtMapper;

    private ISysUserService sysUserService;

    @Autowired
    public SysFunctionServiceImpl(SysFunctionMapper sysFunctionMapper, ISysFunctionExtMapper sysFunctionExtMapper) {
        this.sysFunctionMapper = sysFunctionMapper;
        this.sysFunctionExtMapper = sysFunctionExtMapper;
    }

    @Autowired
    public void setSysUserService(ISysUserService sysUserService) {
        this.sysUserService = sysUserService;
    }

    @Override
    public UnifyResult list(SysFunctionDTO sysFunctionDTO) {
        // SysFunctionExample example = new SysFunctionExample();
        // example.setOrderByClause("func_index ASC");
        // SysFunctionExample.Criteria criteria = example.createCriteria();
        // criteria.andIsDeleteEqualTo(DBYNEnum.N.name());
        // criteria.andIsValidEqualTo(DBYNEnum.Y.name());
        // List<SysFunction> funcList = sysFunctionMapper.selectByExample(example);

        QueryWrapper<SysFunction> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByAsc(SysFunction.COL_FUNC_INDEX);
        queryWrapper.eq(SysFunction.COL_IS_DELETE, DBYNEnum.N.name());
        queryWrapper.eq(SysFunction.COL_IS_VALID, DBYNEnum.Y.name());
        List<SysFunction> funcList = sysFunctionMapper.selectList(queryWrapper);

        List<SysFunctionDTO> treeList = getTreeList(funcList, null);
        return UnifyResult.success().mapData().put("rows", treeList);
    }

    private List<SysFunctionDTO> getTreeList(List<SysFunction> funcList, SysFunctionDTO parent) {
        List<SysFunctionDTO> treeList = new ArrayList<>();
        int funcType = parent == null ? 0 : 1;
        for (SysFunction func : funcList) {
            if (func.getFuncType() != funcType) {
                continue;
            }
            // 一级菜单
            if (parent == null) {
                SysFunctionDTO dto = new SysFunctionDTO(func);
                dto.setChildren(getTreeList(funcList, dto));
                dto.setHasChildren(CollectionUtils.isNotEmpty(dto.getChildren()));
                treeList.add(dto);
                continue;
            }
            if (Objects.equals(func.getPid(), parent.getId())) {
                SysFunctionDTO dto = new SysFunctionDTO(func);
                dto.setChildren(getTreeList(funcList, dto));
                dto.setHasChildren(CollectionUtils.isNotEmpty(dto.getChildren()));
                treeList.add(dto);
            }
        }

        return treeList;
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public UnifyResult add(SysFunctionDTO sysFunctionDTO) {
        UnifyResult result = checkSysFunctionDTO(sysFunctionDTO, Boolean.FALSE);
        if (UnifyResultUtil.isFail(result)) {
            return result;
        }

        CustomLoginUser customLoginUser = ShiroUtil.currentLoginUser();
        Date now = new Date();
        SysFunction sysFunction = new SysFunction();
        sysFunction.setPid(sysFunctionDTO.getPid());
        // sysFunction.setFuncCode(StringUtils.trimToEmpty(sysFunctionDTO.getFuncCode()));
        sysFunction.setTitle(StringUtils.trimToEmpty(sysFunctionDTO.getTitle()));
        sysFunction.setUrl(StringUtils.trimToEmpty(sysFunctionDTO.getUrl()));
        sysFunction.setIcon(StringUtils.trimToEmpty(sysFunctionDTO.getIcon()));
        sysFunction.setFuncType(sysFunctionDTO.getFuncType());
        sysFunction.setPerms(StringUtils.trimToEmpty(sysFunctionDTO.getPerms()));
        sysFunction.setPermsType(StringUtils.trimToNull(sysFunctionDTO.getPermsType()));
        sysFunction.setFuncIndex(sysFunctionDTO.getFuncIndex());
        sysFunction.setHidden(sysFunctionDTO.getHidden());
        sysFunction.setDescription(StringUtils.trimToNull(sysFunctionDTO.getDescription()));
        sysFunction.setIsValid(DBYNEnum.Y.name());
        sysFunction.setIsDelete(DBYNEnum.N.name());
        sysFunction.setCreateBy(customLoginUser.getId());
        sysFunction.setCreateTime(now);
        sysFunction.setUpdateBy(0L);
        sysFunction.setUpdateTime(now);

        sysFunctionMapper.insertSelective(sysFunction);
        return UnifyResult.success();
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public UnifyResult update(SysFunctionDTO sysFunctionDTO) {
        UnifyResult result = checkSysFunctionDTO(sysFunctionDTO, Boolean.TRUE);
        if (UnifyResultUtil.isFail(result)) {
            return result;
        }

        Long id = sysFunctionDTO.getId();
        SysFunction exists = sysFunctionMapper.selectById(id);
        if (exists == null) {
            log.warn("The SysFunction no exists. [id={}]", id);
            return UnifyResult.fail(UnifyResultCode.SERVICE_ERROR, "数据不存在或已被删除");
        }

        Date now = new Date();
        CustomLoginUser customLoginUser = ShiroUtil.currentLoginUser();
        SysFunction sysFunction = new SysFunction();
        sysFunction.setId(id);
        // sysFunction.setFuncCode(StringUtils.trimToNull(sysFunctionDTO.getFuncCode()));
        sysFunction.setTitle(StringUtils.trimToNull(sysFunctionDTO.getTitle()));
        sysFunction.setUrl(StringUtils.trimToNull(sysFunctionDTO.getUrl()));
        sysFunction.setIcon(StringUtils.trimToNull(sysFunctionDTO.getIcon()));
        sysFunction.setFuncType(sysFunctionDTO.getFuncType());
        sysFunction.setPerms(StringUtils.trimToEmpty(sysFunctionDTO.getPerms()));
        sysFunction.setPermsType(StringUtils.trimToNull(sysFunctionDTO.getPermsType()));
        sysFunction.setFuncIndex(sysFunctionDTO.getFuncIndex());
        sysFunction.setHidden(sysFunctionDTO.getHidden());
        sysFunction.setDescription(StringUtils.trimToNull(sysFunctionDTO.getDescription()));
        sysFunction.setUpdateBy(customLoginUser.getId());
        sysFunction.setUpdateTime(now);
        String isDelete = sysFunctionDTO.getIsDelete();
        if (StringUtils.isNotBlank(isDelete) && StringUtils.equalsAny(isDelete, DBYNEnum.Y.name(), DBYNEnum.N.name())) {
            sysFunction.setIsDelete(isDelete);
        }
        String isValid = sysFunctionDTO.getIsValid();
        if (StringUtils.isNotBlank(isValid) && StringUtils.equalsAny(isValid, DBYNEnum.Y.name(), DBYNEnum.N.name())) {
            sysFunction.setIsValid(isValid);
        }

        sysFunctionMapper.updateByPrimaryKeySelective(sysFunction);
        return UnifyResult.success();
    }

    private UnifyResult checkSysFunctionDTO(SysFunctionDTO sysFunctionDTO, boolean isUpdate) {
        // 菜单类型(0:一级菜单; 1:子菜单:2:按钮权限)
        Integer funcType = sysFunctionDTO.getFuncType();
        if (funcType != 0) {
            Long pid = sysFunctionDTO.getPid();
            if (pid == null || pid <= 0L) {
                return UnifyResult.fail(I18NUtil.getMsg("validations.sys.function.invalid.blank.pid"));
            } else {
                sysFunctionDTO.setPid(pid);
            }
        }

        // 一级菜单 icon 必填
        if (funcType == 0 && StringUtils.isBlank(sysFunctionDTO.getIcon())) {
            return UnifyResult.fail(I18NUtil.getMsg("validations.sys.function.invalid.blank.icon"));
        }

        // 子菜单 url 必填
        if (funcType == 1 && StringUtils.isBlank(sysFunctionDTO.getUrl())) {
            return UnifyResult.fail(I18NUtil.getMsg("validations.sys.function.invalid.blank.url"));
        }

        if (isUpdate) {
            // 上级菜单不能是自己本省
            if (funcType != 0 && Objects.equals(sysFunctionDTO.getId(), sysFunctionDTO.getPid())) {
                return UnifyResult.fail(I18NUtil.getMsg("validations.sys.function.invalid.blank.pid"));
            }
        }

        return UnifyResult.success();
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public UnifyResult batchDelete(SysFunctionDTO sysFunctionDTO) {
        List<Long> sysids = EntityIdUtils.parseIds(sysFunctionDTO.getSysids());

        SysFunction params = new SysFunction();
        long currentUserId = ShiroUtil.getCurrentUserId();
        params.setUpdateBy(currentUserId);
        params.setUpdateTime(new Date());
        params.setIsDelete(DBYNEnum.Y.name());
        params.setIsValid(DBYNEnum.N.name());

        UpdateWrapper<SysFunction> updateWrapper = new UpdateWrapper<>();
        updateWrapper.in(SysFunction.COL_ID, sysids);

        int resInt = sysFunctionMapper.update(params, updateWrapper);
        if (resInt != CollectionUtils.size(sysids)) {
            throw new ServiceException(I18NUtil.getMsg("validations.sys.function.no.exists.or.delete"));
        }
        return UnifyResult.success();
    }

    @Override
    public UnifyResult getUserPermissionByToken(String token) {
        if (StringUtils.isBlank(token)) {
            return UnifyResult.fail("请求令牌无效");
        }
        log.debug("------ 通过令牌获取用户拥有的访问菜单 ---- TOKEN ------ {}", token);
        // String username = JwtUtil.getUsername(token);
        long sysuserid = ShiroUtil.getCurrentUserId();

        // 获取所有的角色
        List<SysRole> roles = sysUserService.getUserRoleBySysUserid(sysuserid);
        if (CollectionUtils.isEmpty(roles)) {
            return UnifyResult.fail(I18NUtil.getMsg("user.own.no.roles"));

        }

        List<Long> sysroleids = new ArrayList<>();
        for (SysRole role : roles) {
            sysroleids.add(role.getId());
        }

        // 根据角色获取菜单
        List<SysFunction> funcList = sysFunctionExtMapper.selectBySysroleids(sysroleids);
        if (CollectionUtils.isEmpty(funcList)) {
            return UnifyResult.fail(I18NUtil.getMsg("user.no.functions.available"));
        }

        //// 获取列表
        // SysFunctionExample example = new SysFunctionExample();
        // example.setOrderByClause("func_type ASC, func_index ASC");
        // List<SysFunction> funcList = sysFunctionMapper.selectByExample(example);

        // 生成菜单
        List<MenuVO> menus = genMenuTree(null, funcList);

        return UnifyResult.success().mapData().put("menus", menus);
    }

    @Override
    public UnifyResult delete(SysFunctionDTO sysFunctionDTO) {
        SysFunction existsFunc = sysFunctionMapper.selectById(sysFunctionDTO.getId());
        if (existsFunc == null) {
            log.debug("Invalid id [{}]", sysFunctionDTO.getId());
            return UnifyResult.fail(I18NUtil.getMsg("validations.sys.function.no.exists.or.delete"));
        }

        List<SysFunction> subFuncs = sysFunctionExtMapper.selectByPid(existsFunc.getId());
        if (CollectionUtils.isNotEmpty(subFuncs)) {
            log.debug("Has children functions.");
            return UnifyResult.fail(I18NUtil.getMsg("message.sys.function.delete.has.children"));
        }

        sysFunctionMapper.deleteById(existsFunc.getId());
        // TODO 删除关联关系


        return UnifyResult.success();
    }

    private List<MenuVO> genMenuTree(MenuVO parent, List<SysFunction> funcList) {
        List<MenuVO> menus = new ArrayList<>();
        int funcType = parent == null ? 0 : 1;
        for (SysFunction func : funcList) {
            if (func.getFuncType() != funcType) {
                continue;
            }

            // 一级菜单
            if (parent == null) {
                MenuVO menu = convert(func);
                menu.setSub(genMenuTree(menu, funcList));
                menus.add(menu);
                continue;
            }

            if (Objects.equals(func.getPid(), parent.getId())) {
                MenuVO menu = convert(func);
                menu.setSub(genMenuTree(menu, funcList));
                menus.add(menu);
            }
        }
        return menus;
    }

    private MenuVO convert(SysFunction func) {
        MenuVO menu = new MenuVO();
        menu.setId(func.getId());
        menu.setPid(func.getPid());
        menu.setTitle(func.getTitle());
        menu.setIcon(func.getIcon());
        menu.setUrl(func.getUrl());
        menu.setSub(Lists.newArrayList());
        return menu;
    }
}
